#include "ftpclient.hpp"
#include <cstdio>
#include <process.h>
#include "fileio.hpp"
FtpClient::FtpClient(const string& hostname, const string& user, const string& pwd)
	:_user(user), _pwd(pwd), _env(SocketEnv::getinstance())
{
	struct addrinfo hints;
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_flags = AI_CANONNAME;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	//throw exception
	getaddrinfo(hostname.c_str(), "ftp", &hints, &_ctrlServ);
	_ctrlSock = socket(_ctrlServ->ai_family, _ctrlServ->ai_socktype, _ctrlServ->ai_protocol);
	_myIO = new MyIO;
}

FtpClient::FtpClient(const string& ip, const string &port, const string &user, const string &pwd)
	:_user(user), _pwd(pwd)
{
	struct addrinfo hints;
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	//throw exception
	getaddrinfo(ip.c_str(), port.c_str(), &hints, &_ctrlServ);
	_ctrlSock = socket(_ctrlServ->ai_family, _ctrlServ->ai_socktype, _ctrlServ->ai_protocol);
}

void FtpClient::login()
{
	//throw exception
	connect(_ctrlSock, _ctrlServ->ai_addr, _ctrlServ->ai_addrlen);
	_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
	string cmd;
	cmd += "USER " + _user + "\r\nPASS " + _pwd + "\r\nTYPE A\r\n";
	_myIO->writen(_ctrlSock, cmd.c_str(), cmd.size());
	_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
	_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
	_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
}

void FtpClient::logout()
{
	string cmd;
	cmd += "QUIT\r\n";
	_myIO->writen(_ctrlSock, cmd.c_str(), cmd.size());
	_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
}

void FtpClient::setType(TYPE t)
{
	string cmd;
	switch (t)
	{
	case ASCI:
		cmd = "TYPE A\r\n";
		break;
	case BINARY:
		cmd = "TYPE I\r\n";
		break;
	}
	_myIO->writen(_ctrlSock, cmd.c_str(), cmd.size());
	_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
	
}

void FtpClient::getList()
{
	string cmd;
	cmd += "PASV\r\n";
	_myIO->writen(_ctrlSock, cmd.c_str(), cmd.size());
	_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
	string tmp(linebuf);
	if (tmp.find("227") != string::npos)
	{
		size_t s, e;
		s = tmp.find('(');
		e = tmp.find(')');
		tmp = tmp.substr(s + 1, e - s - 1);
		int p[6];
		sscanf_s(tmp.c_str(), "%d,%d,%d,%d,%d,%d", p, p + 1, p + 2, p + 3, p + 4, p + 5);
		char ip[17];
		char port[6];
		ZeroMemory(ip, sizeof(ip));
		sprintf_s(ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
		sprintf_s(port, "%d", p[4] * 256 + p[5]);
		
		struct addrinfo hints;
		ZeroMemory(&hints, sizeof(hints));
		hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
		hints.ai_family = AF_INET;
		hints.ai_socktype = SOCK_STREAM;
		getaddrinfo(ip, port, &hints, &_dataServ);
		_dataSock = socket(_dataServ->ai_family, _dataServ->ai_socktype, _dataServ->ai_protocol);
		connect(_dataSock, _dataServ->ai_addr, _dataServ->ai_addrlen);
		cmd = "LIST\r\n";
		_myIO->writen(_ctrlSock, cmd.c_str(), cmd.size());
		_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
		//HANDLE tid =(HANDLE)CreateThread(NULL, 0, fun, this, 0, NULL);
		HANDLE tid = (HANDLE)_beginthreadex(NULL, 0, fun, this, 0, NULL);
		_myIO->readline(_ctrlSock, linebuf, sizeof(linebuf));
		WaitForSingleObject(tid, INFINITE);
	}



}
//227 Entering Passive Mode (121,43,112,191,165,150).

FtpClient::~FtpClient()
{
	freeaddrinfo(_ctrlServ);
	freeaddrinfo(_dataServ);
	delete(_myIO);
}

unsigned int __stdcall fun(void *lpParam)
{
	FtpClient *cli = (FtpClient*)lpParam;
	char buf[4096];
	ZeroMemory(buf, 4096);
	WSABUF wsabuf;
	wsabuf.buf = buf;
	wsabuf.len = 4096;
	DWORD flags = 0,nc;
	//HANDLE hfile = CreateFile(TEXT("text.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
	FtpWriteFile f(TEXT("hehe.dat"));
	f.open();
	WSARecv(cli->_dataSock, &wsabuf, 1, &nc, &flags, NULL, NULL);
	while (nc>0)
	{
		//WriteFile(hfile, wsabuf.buf, wsabuf.len, &nwritten, NULL);
		f.write(wsabuf.buf,nc);
		WSARecv(cli->_dataSock, &wsabuf, 1, &nc, &flags, NULL, NULL);
	}
	f.close();
	return 0;
}

